﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Components.Web;
using IServices;
using Microsoft.Extensions.Options;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using Models;
using Common;

namespace WebApi.Middlewares
{
    // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
    public class JwtMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly AppSettings _appSettings;
        private JwtHelper _jwtHelper;

        // 中间件的构造函数只允许单例模式的注入(AddSingleton)，不允许AddScoped注入，所以JwtHelper的注入要放到Invoke中
        public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
        {
            _next = next;
            _appSettings = appSettings.Value;
        }

        //这里虽然不是构造函数，但是依然可以依赖注入
        public async Task Invoke(HttpContext httpContext, IUserService userService, JwtHelper jwtHelper)
        {
            _jwtHelper = jwtHelper;
            //因为token是类似：Bear xxxxx 的形式，所以按空格分隔，只取最后的部分
            var token = httpContext.Request.Headers["token"].FirstOrDefault()?.Split(" ").Last();
            if (token != null)
                attachUserToContext(httpContext, userService, token);

            await _next(httpContext);
        }

        void attachUserToContext(HttpContext httpContext, IUserService userService, string token)
        {
            try
            {
                var jwtToken = _jwtHelper.ValidateJwtToken(token);
                var userId = int.Parse(jwtToken.Claims.First(m => m.Type == "id").Value);
                // attach user to context on successful jwt validation
                httpContext.Items["User"] = userService.GetByID(userId);
            }
            catch
            {
                // do nothing if jwt validation fails
                // user is not attached to context so request won't have access to secure routes
            }
        }
    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class JwtMiddlewareExtensions
    {
        public static IApplicationBuilder UseJwtMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<JwtMiddleware>();
        }
    }
}
